﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Net;

namespace WebProxy_MMTNC
{
    class Cache
    {
        public class CacheKey
        {
            public String AbsoluteUri { get; set; }
            public String UserAgent { get; set; }

            public CacheKey(String requestUri, String userAgent)
            {
                AbsoluteUri = requestUri;
                UserAgent = userAgent;
            }
        }

        public class CacheEntry
        {
            public String AbsoluteUri { get; set; }
            public String UserAgent { get; set; }
            public DateTime? Expires { get; set; }
            public DateTime DateStored { get; set; }
            public Byte[] ResponseBytes { get; set; }
            public HttpStatusCode StatusCode { get; set; }
            public String StatusDescription { get; set; }
            public List<Tuple<String, String>> Headers { get; set; }
            public Boolean FlagRemove { get; set; }
        }

        public class ProxyCache
        {
            private static Hashtable _cache = new Hashtable();
            private static Object _cacheLockObj = new object();
            private static Object _statsLockObj = new object();

            public static CacheEntry GetData(HttpWebRequest request)
            {
                CacheKey key = new CacheKey(request.RequestUri.AbsoluteUri, request.UserAgent);
                if (_cache[key] != null)
                {
                    CacheEntry entry = (CacheEntry)_cache[key];
                    if (entry.FlagRemove || (entry.Expires.HasValue && entry.Expires < DateTime.Now))
                    {
                        entry.FlagRemove = true;
                        return null;
                    }
                    return entry;
                }
                return null;
            }

            public static CacheEntry MakeEntry(HttpWebRequest request, HttpWebResponse response, List<Tuple<String, String>> headers, DateTime? expires)
            {
                CacheEntry newEntry = new CacheEntry();
                newEntry.Expires = expires;
                newEntry.DateStored = DateTime.Now;
                newEntry.Headers = headers;
                newEntry.AbsoluteUri = request.RequestUri.AbsoluteUri;
                newEntry.UserAgent = request.UserAgent;
                newEntry.StatusCode = response.StatusCode;
                newEntry.StatusDescription = response.StatusDescription;
                if (response.ContentLength > 0)
                    newEntry.ResponseBytes = new Byte[response.ContentLength];
                return newEntry;
            }

            public static void AddData(CacheEntry entry)
            {

                if (!_cache.Contains(entry.AbsoluteUri) && !_cache.Contains(entry.UserAgent))
                {
                    _cache.Add(entry.AbsoluteUri, entry);
                    _cache.Add(entry.UserAgent, entry);
                }
            }

            public static Boolean CanCache(WebHeaderCollection headers, ref DateTime? expires)
            {

                foreach (String s in headers.AllKeys)
                {
                    String value = headers[s].ToLower();
                    switch (s.ToLower())
                    {
                        case "cache-control":
                            if (value.Contains("max-age"))
                            {
                                int seconds;
                                if (int.TryParse(value, out seconds))
                                {
                                    if (seconds == 0)
                                        return false;
                                    DateTime d = DateTime.Now.AddSeconds(seconds);
                                    if (!expires.HasValue || expires.Value < d)
                                        expires = d;

                                }
                            }

                            if (value.Contains("private") || value.Contains("no-cache"))
                                return false;
                            else if (value.Contains("public") || value.Contains("no-store"))
                                return true;

                            break;

                        case "pragma":

                            if (value == "no-cache")
                                return false;

                            break;
                        case "expires":
                            DateTime dExpire;
                            if (DateTime.TryParse(value, out dExpire))
                            {
                                if (!expires.HasValue || expires.Value < dExpire)
                                    expires = dExpire;
                            }
                            break;
                    }
                }
                return true;
            }

        }
    }
}
